#!/bin/bash
# MySQL参数配置错误（my.cnf）自动修复脚本
FIX_CODE_ID="mysql_config"


# 配置参数 - 根据实际环境修改
MYSQL_USER="root"                  # MySQL管理员用户
MYSQL_PASSWORD="your_mysql_password"# MySQL密码
MYSQL_HOST="localhost"             # MySQL主机地址
MYSQL_PORT=3306                    # MySQL端口
CONFIG_FILES=(                     # MySQL配置文件路径列表
    "/etc/my.cnf"
    "/etc/mysql/my.cnf"
    "/usr/local/mysql/etc/my.cnf"
)
BACKUP_DIR="/var/backups/mysql_config"  # 配置文件备份目录
VALID_CONFIG_TEMPLATE="/etc/mysql/my.cnf.template"  # 有效配置模板路径
LOG_FILE="/var/log/mysql_config_fix.log"
MAX_BACKUP_COUNT=5                 # 保留的最大备份数量

# 日志函数
log() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

# 执行MySQL命令的封装函数
mysql_cmd() {
    local query=$1
    mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -h"$MYSQL_HOST" -P"$MYSQL_PORT" -N -B -e "$query" 2>/dev/null
}

# 检查MySQL服务状态
check_mysql_running() {
    if systemctl is-active --quiet mysql; then
        return 0
    else
        return 1
    fi
}

# 检查MySQL配置文件语法
check_config_syntax() {
    log "检查MySQL配置文件语法"
    
    # 使用mysqld --help --verbose检查配置文件
    local check_output=$(mysqld --help --verbose 2>&1)
    
    if echo "$check_output" | grep -q "unknown variable" || echo "$check_output" | grep -q "Invalid configuration"; then
        log "检测到配置文件语法错误: $(echo "$check_output" | grep -E "unknown variable|Invalid configuration" | head -1)"
        return 1
    else
        log "配置文件语法检查通过"
        return 0
    fi
}

# 查找实际使用的配置文件
find_active_config() {
    for file in "${CONFIG_FILES[@]}"; do
        if [ -f "$file" ]; then
            # 检查MySQL是否实际使用该配置文件
            if mysql_cmd "SHOW VARIABLES LIKE 'config_file'" | grep -q "$file"; then
                echo "$file"
                return 0
            fi
        fi
    done
    
    # 如果未找到，返回第一个存在的配置文件
    for file in "${CONFIG_FILES[@]}"; do
        if [ -f "$file" ]; then
            echo "$file"
            return 0
        fi
    done
    
    return 1
}

# 备份配置文件
backup_config() {
    local config_file=$1
    
    # 确保备份目录存在
    mkdir -p "$BACKUP_DIR"
    
    # 创建带时间戳的备份
    local timestamp=$(date +'%Y%m%d_%H%M%S')
    local backup_file="${BACKUP_DIR}/my.cnf_${timestamp}.bak"
    
    if cp "$config_file" "$backup_file"; then
        log "已备份配置文件到: $backup_file"
        
        # 清理旧备份
        local backups=($(ls -t "${BACKUP_DIR}/my.cnf_"*.bak 2>/dev/null))
        if [ ${#backups[@]} -gt $MAX_BACKUP_COUNT ]; then
            for ((i=MAX_BACKUP_COUNT; i<${#backups[@]}; i++)); do
                rm -f "${backups[$i]}"
                log "已清理旧备份: ${backups[$i]}"
            done
        fi
        return 0
    else
        log "配置文件备份失败"
        return 1
    fi
}

# 恢复最近的备份配置
restore_last_backup() {
    local config_file=$1
    
    # 查找最近的备份
    local last_backup=$(ls -t "${BACKUP_DIR}/my.cnf_"*.bak 2>/dev/null | head -1)
    
    if [ -z "$last_backup" ]; then
        log "没有找到配置文件备份"
        return 1
    fi
    
    log "从备份恢复配置文件: $last_backup"
    
    if cp "$last_backup" "$config_file"; then
        log "配置文件恢复成功"
        return 0
    else
        log "配置文件恢复失败"
        return 1
    fi
}

# 使用模板修复配置文件
fix_with_template() {
    local config_file=$1
    
    if [ ! -f "$VALID_CONFIG_TEMPLATE" ]; then
        log "配置模板文件不存在: $VALID_CONFIG_TEMPLATE"
        return 1
    fi
    
    log "使用模板文件修复配置: $VALID_CONFIG_TEMPLATE"
    
    # 保留原始配置中的关键路径信息
    local datadir=$(grep -E "^datadir" "$config_file" | head -1)
    local socket=$(grep -E "^socket" "$config_file" | head -1)
    local pid_file=$(grep -E "^pid-file" "$config_file" | head -1)
    
    # 复制模板文件
    if cp "$VALID_CONFIG_TEMPLATE" "$config_file"; then
        # 恢复关键路径配置
        if [ -n "$datadir" ]; then
            sed -i "s|^datadir.*|$datadir|" "$config_file"
        fi
        if [ -n "$socket" ]; then
            sed -i "s|^socket.*|$socket|" "$config_file"
        fi
        if [ -n "$pid_file" ]; then
            sed -i "s|^pid-file.*|$pid_file|" "$config_file"
        fi
        
        log "使用模板修复配置文件成功"
        return 0
    else
        log "使用模板修复配置文件失败"
        return 1
    fi
}

# 修复已知的无效参数
fix_known_invalid_params() {
    local config_file=$1
    
    log "尝试修复已知的无效参数"
    
    # 已知的无效/已废弃参数列表及其替代方案
    # 格式: "废弃参数=替代参数"
    local deprecated_params=(
        "query_cache_size= #"  # 查询缓存已在MySQL 8.0中移除
        "query_cache_type= #"
        "innodb_large_prefix= #"  # MySQL 8.0中已废弃
        "log_slave_updates= #"    # 特定场景下需要，默认注释
        "sync_frm= #"             # MySQL 5.7.8后已废弃
    )
    
    # 替换无效参数
    for param in "${deprecated_params[@]}"; do
        local old_param=$(echo "$param" | cut -d'=' -f1)
        local new_param=$(echo "$param" | cut -d'=' -f2-)
        
        if grep -qE "^${old_param}" "$config_file"; then
            log "修复参数: $old_param -> $new_param"
            sed -i "s|^${old_param}.*|${old_param}=${new_param}  # 自动修复: 已废弃参数|" "$config_file"
        fi
    done
    
    return 0
}

# 重启MySQL服务
restart_mysql() {
    log "尝试重启MySQL服务"
    
    if systemctl restart mysql; then
        log "MySQL服务重启成功"
        # 等待服务就绪
        sleep 10
        if check_mysql_running; then
            return 0
        else
            log "MySQL服务重启后未正常运行"
            return 1
        fi
    else
        log "MySQL服务重启失败"
        return 1
    fi
}

# 主逻辑
main() {
    log "开始MySQL配置文件检查与修复"
    
    # 查找活跃的配置文件
    local active_config=$(find_active_config)
    if [ -z "$active_config" ]; then
        log "未找到MySQL配置文件，无法继续"
        exit 1
    fi
    log "检测到活跃配置文件: $active_config"
    
    # 检查配置文件语法
    if check_config_syntax; then
        log "MySQL配置文件无错误"
        exit 0
    fi
    
    # 配置文件有错误，开始修复流程
    log "启动配置文件修复流程"
    
    # 步骤1: 备份当前配置
    backup_config "$active_config"
    
    # 步骤2: 尝试修复已知的无效参数
    fix_known_invalid_params "$active_config"
    
    # 检查修复效果
    if check_config_syntax; then
        log "已知无效参数修复成功"
        # 重启服务使配置生效
        restart_mysql
        exit $?
    fi
    
    # 步骤3: 尝试从备份恢复
    if restore_last_backup "$active_config"; then
        # 检查恢复后的配置
        if check_config_syntax; then
            log "从备份恢复配置成功"
            # 重启服务
            restart_mysql
            exit $?
        else
            log "备份的配置文件同样存在错误"
        fi
    fi
    
    # 步骤4: 使用模板文件修复
    if fix_with_template "$active_config"; then
        if check_config_syntax; then
            log "使用模板修复配置成功"
            # 重启服务
            restart_mysql
            exit $?
        else
            log "模板修复后的配置仍有错误"
        fi
    fi
    
    # 所有修复尝试失败
    log "所有修复措施均失败，需要人工干预"
    exit 1
}

# 执行主逻辑
main
    